#ifndef __SOCKET_HPP__

#include "Logger.hpp"
#include "InetAddr.hpp"
#include <iostream>
#include <string>
#include <stdlib.h>
#include <unistd.h>
#include <memory>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
// 封装套接字
static const int gsockfd = -1;
static int gbacklog = 8;

enum
{
    OK,
    CREATE_ERR,
    BIND_ERR,
    LISTEN_ERR
};

class Socket
{
public:
    virtual void CreatSocketOrDie() = 0;
    virtual void BindSocketOrDie(int port) = 0;
    virtual void ListenSocketOrDie(int gbacklog) = 0;
    virtual std::shared_ptr<Socket> AcceptSocketOrDie(InetAddr *clientaddr) = 0;
    virtual int Sockfd() = 0;
    virtual void Close() = 0;
    virtual ssize_t Recv(std::string *out) = 0;
    virtual ssize_t Send(const std::string &in) = 0;
    virtual bool Connect(InetAddr &peer) = 0;

public:
    void BuildListenSocketMethod(int _port)
    {
        CreatSocketOrDie();
        BindSocketOrDie(_port);
        ListenSocketOrDie(gbacklog);
    }
    void BuildClientSocketMethod()
    {
        CreatSocketOrDie();
    }
};

class TcpSocket : public Socket
{
public:
    TcpSocket()
        : _sockfd(gsockfd)
    {
    }
    TcpSocket(int sockfd) : _sockfd(sockfd)
    {
    }
    // 创建套接字
    void CreatSocketOrDie() override
    {
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
        {
            LOG(LogLevel::ERROR) << "create socket error!";
            exit(CREATE_ERR);
        }
        LOG(LogLevel::INFO) << "create socket success!";
    }
    // 绑定套接字
    void BindSocketOrDie(int port) override
    {
        InetAddr local(port);
        if (bind(_sockfd, local.Addr(), local.Length()) != 0)
        {
            LOG(LogLevel::ERROR) << "bind socket error!";
            exit(BIND_ERR);
        }
        LOG(LogLevel::INFO) << "bind socket success!";
    }
    // 监听连接
    void ListenSocketOrDie(int gbacklog) override
    {
        if (listen(_sockfd, gbacklog) != 0)
        {
            LOG(LogLevel::ERROR) << "listen socket error!";
            exit(LISTEN_ERR);
        }
        LOG(LogLevel::INFO) << "listen socket success!";
    }
    // 连接客户端
    std::shared_ptr<Socket> AcceptSocketOrDie(InetAddr *clientaddr) override
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        int fd = accept(_sockfd, (struct sockaddr *)&peer, &len);
        if (fd != 0)
        {
            LOG(LogLevel::WARNING) << "accept socket error!";
            return nullptr;
        }
        LOG(LogLevel::INFO) << "accept socket success!";
        // 把客户端的地址拿出来
        clientaddr->Init(peer);

        return std::make_shared<TcpSocket>(fd);
    }

    ssize_t Recv(std::string *out) override
    {
        // 只读一次
        char buffer[1024];
        ssize_t n = recv(_sockfd, buffer, sizeof(buffer) - 1, 0);
        if (n > 0)
        {
            buffer[n] = 0;
            *out += buffer; // 故意+=
        }
        return n;
    }
    ssize_t Send(const std::string &in)
    {
        return send(_sockfd, in.c_str(), in.size(), 0);
    }
    bool Connect(InetAddr &peer) override
    {
        int n = connect(_sockfd, peer.Addr(), peer.Length());
        if (n >= 0)
            return true;
        else
            return false;
    }

    int Sockfd() override
    {
        return _sockfd;
    }
    void Close() override
    {
        if (_sockfd >= 0)
            close(_sockfd);
    }
    ~TcpSocket()
    {
    }

private:
    int _sockfd;
};

#endif